#include "main.h"
#include "mb_include.h"
#include "FreeRTOS.h"
#include "cmsis_os.h"
#include "string.h"
#include "userModbus.h"
#include "lora.h"
#include "swInfo.h"


typedef struct {                                 
  uint8_t  	add;                             
  uint8_t  	cmd;                             
  uint8_t	dataBuf[16];
  uint8_t	dataLen;
	uint8_t passThough;		//是否需要透传，0-正常 1-透传
}mbMesType;

osMailQDef(mbSendMail,40, mbMesType);                    // Define mail queue
osMailQId  mbSendMail;

extern osMutexId mbInfoMuxHandle;

void umb_init()
{
	/*modbus 主机串口初始化*/
	mbh_init(19200,MB_PARITY_NONE,2);	
	mbSendMail = osMailCreate(osMailQ(mbSendMail), NULL);      // create mail queue

}
uint16_t testCounter=0;
//数据存入modbus发送队列
//add-地址 cmd-命令  data-数据（不包含crc） 	 datalen-数据长度  flag-是否透传标志
uint8_t umb_putSendQueue(uint8_t add,uint8_t cmd,uint8_t *data,uint8_t datalen,uint8_t flag)
{
  mbMesType *pmes;
	pmes=osMailAlloc(mbSendMail, 0);
	if(pmes==NULL)return 0;
	pmes->add=add;
	pmes->cmd=cmd;
	pmes->dataLen=datalen;
	pmes->passThough=flag;
	memcpy(pmes->dataBuf,data,datalen);	
	osMailPut(mbSendMail,pmes);
	return 1;	
}
//获取开关是否存在，对应modbus 0x01指令
void umb_getSwNum()
{
	uint8_t cmdbuf[4];
	cmdbuf[0]=0x00;   //开关起始地址
	cmdbuf[1]=0x00;		
	cmdbuf[2]=0X00;		//0X00FF为获取开关是否存在指令		
	cmdbuf[3]=0XFF;	
	umb_putSendQueue(0x01,0x01,cmdbuf,4,0);	
}
//获取开关状态，对应modbus 0X01指令
void umb_getSwState()
{
	uint8_t cmdbuf[4];
	cmdbuf[0]=0x00;   
	cmdbuf[1]=0x00;		//开关起始地址
	cmdbuf[2]=SW_MAX_NUMBER>>8;		//开关数量高位
	cmdbuf[3]=SW_MAX_NUMBER&0xff;	//开关数量地位
	umb_putSendQueue(0x01,0x01,cmdbuf,4,0);
}
//获取开关是否可以远控，对应modbus指令 0x02
void umb_getSwConFlag()
{
	uint8_t cmdbuf[4];
	cmdbuf[0]=0x00;   //开关起始地址
	cmdbuf[1]=0x00;		
	cmdbuf[2]=SW_MAX_NUMBER>>8;		//开关数量高位		
	cmdbuf[3]=SW_MAX_NUMBER&0xff;	//开关数量地位	
	umb_putSendQueue(0x01,0x02,cmdbuf,4,0);		
}


//获取实时数据 对应modbus 0X03指令
//rtd_add-功能地址，请查看realTimeDataType
void umb_getRealData(uint8_t rtdAdd)
{
	uint8_t cmdbuf[4];
	cmdbuf[0]=rtdAdd;   	//功能地址
	cmdbuf[1]=0x00;				//开关地址
	cmdbuf[2]=(uint8_t)(SW_MAX_NUMBER>>8);				//数据个数高位
	cmdbuf[3]=(uint8_t)SW_MAX_NUMBER&0xff;			//数据个数地位
	umb_putSendQueue(0x01,0x03,cmdbuf,4,0);	
}

//设置一个开关开合闸 对应0x05指令
//swnum:开关编号	state：0-关 1-开
void umb_setOneSw(uint8_t swnum,uint8_t state)
{
	uint8_t cmdbuf[4];
	cmdbuf[0]=0x00;   	
	cmdbuf[1]=swnum;							//开关地址
	if(state==0)cmdbuf[2]=0x00;		//0xFF00-开	0x0000-关
	else cmdbuf[2]=0xFF;
	cmdbuf[3]=0x00;								
	umb_putSendQueue(0x01,0x05,cmdbuf,4,0);		
}


//接收到01命令码回调-获取开关状态、获取开关数
void mbh_hook_rec01(uint8_t add,uint8_t *data,uint8_t datalen)
{
	uint8_t sendlen;
	uint8_t *psbuf;
	uint8_t swNum;
	uint32_t swState;
	//lora_putSendQueue(data,datalen);
	mbh_getSendData(&sendlen,&psbuf);
	if((psbuf[4]==0x00)&&(psbuf[5]==0xff))//用来获取开关是否存在
	{
		swNum=data[1];
		if(data[2]!=0)swNum+=data[2]<<8;
		swinfo_set_number(swNum);
	}
	else if(data[0]==2)
	{
		swState=(data[2]<<8)+data[1];
		swinfo_set_state(swState);
	}
}
//接收到02命令码回调-获取远控标志
void mbh_hook_rec02(uint8_t add,uint8_t *data,uint8_t datalen)
{
	uint32_t flag;
	if(data[0]==2)
	{
		flag=(data[2]<<8)+data[1];
		swinfo_set_conflag(flag);	
	}	
}
//接收到03命令码回调-读取实时数据
void mbh_hook_rec03(uint8_t add,uint8_t *data,uint8_t datalen)
{
	uint8_t sendlen;
	uint8_t *psbuf;
	mbh_getSendData(&sendlen,&psbuf);	 //psbuf[2]为功能地址
	if(data[0]==SW_MAX_NUMBER*2)
	{
		swinfo_set_info(psbuf[2],data+1,SW_MAX_NUMBER);
	}
}
//modbus接收到数据以后透传回调
void mbh_hook_passThrough(uint8_t *rbuf,uint8_t rlen)
{
	//lora_putSendQueue(rbuf,rlen);
	lora_cmd_AckPassThrogh(rbuf,rlen);
}

//轮询通过modbus读取数据
void umb_getPoll()
{
	static uint16_t counter=0;
	static uint8_t info_num=0;
	counter++;
	if(counter==1)umb_getSwNum();
	else if(counter==20)umb_getSwState();
	else if(counter==30)umb_getSwConFlag();
	else if(counter==(3000+info_num*20))
	{
		umb_getRealData(info_num);
		info_num++;
	}
	if(info_num>=SW_INFO_TYPE_NUM)
	{
		counter=0;
		info_num=0;
	}
}

//modbus任务
void ModbusTask(void const * argument)
{
	mbMesType  *pmes;
  osEvent  		evt;
	while(1)
	{
		umb_getPoll();
		mbh_poll();
				
		//处于空闲状态就执行一次发送
		if(mbh_getState()==MBH_STATE_IDLE)	//modbus主机处于空闲状态
		{
			evt = osMailGet(mbSendMail, 0);   // wait for mail
			if (evt.status == osEventMail)
			{
				pmes=evt.value.p;
				if(pmes->passThough==0)
				{
					mbh_send(pmes->add,pmes->cmd,pmes->dataBuf,pmes->dataLen);
				}
				else mbh_sendPassThrough(pmes->add,pmes->cmd,pmes->dataBuf,pmes->dataLen);
				osMailFree(mbSendMail, pmes);
			}			
		}		
		osDelay(1);
	}
}
